package base.dao;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.support.SqlSessionDaoSupport;

import com.sun.tracing.ProbeName;

import base.utils.PageEntity;
import base.utils.PagingResult;
import base.utils.ToMapping;


/**
 * baseDAO的实现基类
 *
 * @author kyq
 *
 * @param <T>
 * @param <PK>
 */
public class BaseDaoImpl<T, PK extends Serializable> extends
        SqlSessionDaoSupport implements BaseDao<T, PK> {
    // mapper.xml中的namespace
    private String namespace = "base";
    //表名
    private String tableName = "";

    // sqlmap.xml定义文件中对应的sqlid
    public static final String SQLID_INSERT = "insertByEntity";
    public static final String SQLID_UPDATE = "updateByEntity";
    public static final String SQLID_DELETE_PK = "deleteByPrimaryKey";
    public static final String SQLID_TRUNCATE = "truncate";
    public static final String SQLID_SELECT = "selectAll";
    public static final String SQLID_SELECT_PK = "selectByPrimaryKey";
    public static final String SQLID_SELECT_PARAM = "selectByExample";
    public static final String SQLID_SELECT_SQL = "selectBySql";
    public static final String SQLID_SELECT_PROCEDURE = "selectByProcedure";
    public static final String SQLID_BATCHUPTADE = "batchUpdateByEntity";

    @Resource(name = "sqlSessionTemplate")
    public void setSuperSqlSessionTemplate(SqlSessionTemplate sqlSessionTemplate) {
        super.setSqlSessionTemplate(sqlSessionTemplate);
    }

	private Class<T> persistentClass;
    
    /** 
     * 用于Dao层子类使用的构造函数. 通过子类的泛型定义取得对象类型 
     */  
	 @SuppressWarnings("unchecked")  
	 public BaseDaoImpl(){  
	     //getClass() 返回表示此 Class 所表示的实体（类、接口、基本类型或 void）的超类的 Class
	     this.persistentClass=(Class<T>)getSuperClassGenricType(getClass(), 0);
    	 tableName = persistentClass.getSimpleName();
	 }  

	 /** 
      * 通过反射, 获得定义Class时声明的父类的泛型参数的类型. 如无法找到, 返回Object.class. 
      *  
      *@param clazz 
      *            clazz The class to introspect 
      * @param index 
      *            the Index of the generic ddeclaration,start from 0. 
      * @return the index generic declaration, or Object.class if cannot be 
      *         determined 
      */  
     @SuppressWarnings("unchecked")  
     public static Class<Object> getSuperClassGenricType(final Class<?> clazz, final int index) {  
           
         //返回表示此 Class 所表示的实体（类、接口、基本类型或 void）的直接超类的 Type。  
         Type genType = clazz.getGenericSuperclass();  
   
         if (!(genType instanceof ParameterizedType)) {  
            return Object.class;  
         }  
         //返回表示此类型实际类型参数的 Type 对象的数组。  
         Type[] params = ((ParameterizedType) genType).getActualTypeArguments();  
   
         if (index >= params.length || index < 0) {  
                      return Object.class;  
         }  
         if (!(params[index] instanceof Class)) {  
               return Object.class;  
         }  
   
         return (Class<Object>) params[index];  
     }
 
    @Override
    public int insertByEntity(T entity) {
        int rows = 0;
        ToMapping tm = new ToMapping();
        tm.setTable(tableName).parseMapping(entity);
        try {
            rows = getSqlSession().insert(namespace + "." + SQLID_INSERT,
            		tm);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rows;
    }

    @Override
    public int updateByEntity(T entity) {
        int rows = 0;
        ToMapping tm = new ToMapping();
        tm.setTable(tableName).parseMapping(entity);
        try {
            rows = getSqlSession().update(namespace + "." + SQLID_UPDATE,
            		tm);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rows;
    }
    
    @Override
    public int batchUpdateByEntity(List<T> entities) {
        int rows = 0;
        try {
        	/*转换实体格式*/
        	List<ToMapping> tms = new ArrayList<ToMapping>();
        	ToMapping tm = null;
        	for(T entity:entities){
        		tm = new ToMapping();
                tm.setTable(tableName).parseMapping(entity);
                tms.add(tm);
            }
        	/*获取每个字段的值的个数*/
        	int[] sum = new int[tms.get(0).getModel().size()];
        	for(ToMapping tmap:tms){
        		List<Map<String,Object>> tmaps = tmap.getModel();
        		for(int index = 0;index < tmaps.size();index++){
        			if(tmaps.get(index).get("varValue") != null){
        				sum[index]++;
        			}
            	}
        	}
        	System.out.println("--test-- sum:" +  Arrays.toString(sum));
        	/*根据个数判断对实体字段进行删减，防止mapping中遍历出错*/
        	int item = 0;
        	for(int i = 0;i < sum.length;i++){
        		if(sum[i] == 0){
        			for(ToMapping tmap:tms){
        				tmap.getModel().remove(item);
        			}
        			item--;
        		}
        		item++;
        	}
        	
            rows = getSqlSession().update(namespace + "." + SQLID_BATCHUPTADE,
            		tms);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rows;
    }

    @Override
    public int deleteByPrimaryKey(PK primaryKey) {
        int rows = 0;
        ToMapping tm = new ToMapping();
        try {
     		T s= persistentClass.newInstance();
            tm.setTable(tableName).parseMapping(s);
            tm.getModel().get(0).put("varValue", primaryKey);
            rows = getSqlSession().delete(namespace + "." + SQLID_DELETE_PK,
                    tm);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return rows;
    }

	public T selectByPrimaryKey(PK primaryKey){
    	Map<?,?> entity = null;
    	ToMapping tm = new ToMapping();
    	T t = null;
    	try {
			T s = persistentClass.newInstance();
			tm.setTable(tableName).parseMapping(s);
			tm.getModel().get(0).put("varValue", primaryKey);
    		entity = getSqlSession().selectOne(namespace + "." + SQLID_SELECT_PK,
    				tm);
			s = ToMapping.mapToModel(persistentClass, entity);
			t = s;
        } catch (Exception e) {
            e.printStackTrace();
        }
    	return t;
    };

	@Override
    public List<T> selectAll(){
    	BaseExample example = new BaseExample();
    	example.setTable(tableName);
    	List<Map<?,?>> list = null;
    	List<T> ts = new ArrayList<T>();
    	try {
    		list = getSqlSession().selectList(namespace + "." + SQLID_SELECT,example);
    		ts = ToMapping.listToModel(persistentClass, list);
    		
    		printLog(SQLID_SELECT_PARAM, example);
        } catch (Exception e) {
            e.printStackTrace();
        }
    	return ts;
    };

    @Override
	public List<Map<?,?>> selectByExample(BaseExample param) {
    	param.setTable(tableName);
    	List<Map<?,?>> list = null;
    	try {
    		list = getSqlSession().selectList(namespace + "." + SQLID_SELECT_PARAM
    				,param);
    		
    		printLog(SQLID_SELECT_PARAM, param);
        } catch (Exception e) {
            e.printStackTrace();
        }
    	return list;
	}

    @Override
    public PagingResult selectPagination(PageEntity pageEntity) {
        try {
            int page = pageEntity.getPage() == null || "".equals(pageEntity.getPage()) ? 1 : pageEntity.getPage(); //默认为第一页
            int size = pageEntity.getSize() == null || "".equals(pageEntity.getSize()) ? 15 : pageEntity.getSize();; //默认每页15个

            RowBounds rowBounds = new RowBounds((page-1)*size, size);

            BaseExample param = pageEntity.getParams();
            param.setTable(tableName);
            List<Map<?,?>> resultList = getSqlSession().selectList(namespace + "." + SQLID_SELECT_PARAM,param,rowBounds);
            int totalSize = selectByExample(pageEntity.getParams()).size();

            PagingResult pagingResult = new PagingResult();
            pagingResult.setCurrentPage(page);
            pagingResult.setTotalSize(totalSize);
            pagingResult.setResultList(resultList);
            
            printLog(SQLID_SELECT_PARAM, param);
            
            return pagingResult;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


	@Override
	public List<Map<?,?>> selectBySql(String[] clause,String sql, Object[] obj) {
		try {
			ToMapping tm = new ToMapping();
			tm.setTable(tableName).setReturnClause(clause)
				.setHql(sql).setObj(obj).end();
			List<Map<?,?>> resultList = getSqlSession().selectList(namespace + "." + SQLID_SELECT_SQL,tm);
			return resultList;
		} catch (Exception e) {
            e.printStackTrace();
            return null;
        }
	}

	@Override
	public PagingResult selectBySqlPaging(String[] clause,String sql,Object[] obj,Integer page,Integer size){
		try {
			page = page == null || "".equals(page) ? 1 : page; //默认为第一页
			size = size == null || "".equals(size) ? 15 : size; //默认每页15个
			RowBounds rowBounds = new RowBounds((page-1)*size, size);
			ToMapping tm = new ToMapping();
			tm.setTable(tableName).setReturnClause(clause)
				.setHql(sql).setObj(obj).end();
			List<Map<?,?>> resultList = getSqlSession().selectList(namespace + "." + SQLID_SELECT_SQL,tm,rowBounds);
			int totalSize = selectBySql(clause,sql,obj).size();

            PagingResult pagingResult = new PagingResult();
            pagingResult.setCurrentPage(page);
            pagingResult.setTotalSize(totalSize);
            pagingResult.setResultList(resultList);
            return pagingResult;
		} catch (Exception e) {
	        e.printStackTrace();
	        return null;
	    }
	}
	
	@Override
	public List<Map<?,?>> selectByProcedure(String procedureName,List<Object> param){
    	List<Map<?,?>> entity = null;
    	Map<String,Object> paramMap = new HashMap<String, Object>();
    	paramMap.put("param", param);
    	paramMap.put("procedureName", procedureName);
    	try {
    		entity = getSqlSession().selectList(namespace + "." + SQLID_SELECT_PROCEDURE,paramMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
    	return entity;
    };

    /**
     * 日志打印
     * @param sqlId
     * @param param
     */
    public void printLog(String sqlId,Object param){
        Configuration configuration = getSqlSession().getConfiguration();
        //sqlId为配置文件中的sqlid
        MappedStatement mappedStatement = configuration.getMappedStatement(sqlId);
        //param为传入到sql语句中的参数
        BoundSql boundSql = mappedStatement.getBoundSql(param);
        //得到sql语句
        String sql = boundSql.getSql().trim();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println("info-sql: "+sdf.format(new Date())+"  "+sql);
    }

}